package com.zjw.zy.componse.demo.view

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.util.Log
import android.view.GestureDetector
import android.view.GestureDetector.SimpleOnGestureListener
import android.view.MotionEvent
import android.view.SurfaceHolder
import android.view.SurfaceView
import com.blankj.utilcode.util.ToastUtils
import com.zjw.zy.componse.demo.R
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors

/**
 * @author ：zhong.jw
 * @date ：Created in 2023/2/20 9:39
 *
 * 五子棋View
 */
class GobangView : SurfaceView, SurfaceHolder.Callback {

    companion object {
        private const val TAG = "GobangView"


        private const val TYPE_NONE = -1
        private const val TYPE_BLACK = 1
        private const val TYPE_WHITE = 2
    }

    private var itemSize: Float = 0f
    private var itemsLength: Float = 0f
    private var offsetY: Float = 0f
    private var offsetX: Float = 0f
    private var renderThread: ExecutorService? = null

    private var mListener: Listener? = null

    private var mHeight = 0
    private var mWidth = 0

    private var mSizeCount = 16

    private var data: Array<IntArray>? = null

    private val pw = Paint().apply {
        this.color = Color.WHITE
    }

    private val pb = Paint().apply {
        this.color = Color.BLACK
    }

    private var isWhiteDo = false

    private var isRunning = false

    private val mGestureDetector = GestureDetector(context, object : SimpleOnGestureListener() {
        override fun onSingleTapUp(e: MotionEvent): Boolean {
            processClickEvent(e)
            return true
        }
    })

    constructor(context: Context?) : super(context) {
        holder.addCallback(this)

        data = Array(mSizeCount) {
            IntArray(mSizeCount) {
                TYPE_NONE
            }
        }

        isRunning = true
    }

    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
    }

    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context, attrs, defStyleAttr
    ) {
    }

    fun initGame(size: Int = 16) {
        mSizeCount = size
        isRunning = true
        isWhiteDo = false
        data = Array(mSizeCount) {
            IntArray(mSizeCount) {
                TYPE_NONE
            }
        }
        renderThread?.submit {
            drawGame()
        }
    }

    override fun surfaceCreated(p0: SurfaceHolder) {
        Log.d(TAG, "surfaceCreated() called with: p0 = $p0")
        renderThread = Executors.newSingleThreadExecutor()
    }

    override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
        Log.d(
            TAG,
            "surfaceChanged() called with: holder = $holder, format = $format, width = $width, height = $height"
        )
        mHeight = height
        mWidth = width

        val padding = 20f
        itemsLength = kotlin.math.min(mHeight, mWidth) - 2 * padding
        itemSize = itemsLength / (mSizeCount - 1)
        offsetX = (mWidth - itemsLength) / 2
        offsetY = (mHeight - itemsLength) / 2
        renderThread?.submit {
            drawGame()
        }
    }

    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent): Boolean {
        Log.d(TAG, "onTouchEvent() called with: event = $event")
        mGestureDetector.onTouchEvent(event)
        return true
    }

    override fun surfaceDestroyed(p0: SurfaceHolder) {
        Log.d(TAG, "surfaceDestroyed() called with: p0 = $p0")
        renderThread?.shutdown()
    }

    private fun processClickEvent(e: MotionEvent) {
        Log.d(TAG, "processClickEvent() called with: e = $e")

        if (!isRunning) {
            return
        }
        renderThread?.submit {
            val (x, y) = computeClickPosition(e)

            if (x == -1 || y == -1) {
                return@submit
            }

            if (data!![y][x] != TYPE_NONE) {
                return@submit
            }

            val white = isWhiteDo

            if (white) {
                data!![y][x] = TYPE_WHITE
            } else {
                data!![y][x] = TYPE_BLACK
            }

            isWhiteDo = !isWhiteDo

            drawGame()

            checkResult(x, y, white)?.let { publishResult(it) }
        }

    }

    private fun publishResult(result: Boolean) {
        if (result) {
            mListener?.onResult(1)
            ToastUtils.showShort("白胜")
        } else {
            mListener?.onResult(2)
            ToastUtils.showShort("黑胜")
        }

        isRunning = false
    }

    /**
     * 检查是否五连
     * @return null未胜 true 白胜 false 黑胜
     * */
    private fun checkResult(x: Int, y: Int, white: Boolean): Boolean? {
        data?.let { arr ->
            val size = arr.size
            var count = 0
            if (white) {
                //check横向
                var i = x - 1
                while (i >= 0) {
                    if (arr[y][i] == TYPE_WHITE) {
                        count++
                        i -= 1
                        continue
                    }
                    break
                }
                i = x + 1
                while (i < size) {
                    if (arr[y][i] == TYPE_WHITE) {
                        count++
                        i += 1
                        continue
                    }
                    break
                }

                if (count >= 4) {
                    return true
                }

                count = 0
                //check纵向
                i = y - 1
                while (i >= 0) {
                    if (arr[i][x] == TYPE_WHITE) {
                        count++
                        i -= 1
                        continue
                    }
                    break
                }
                i = y + 1
                while (i < size) {
                    if (arr[i][x] == TYPE_WHITE) {
                        count++
                        i += 1
                        continue
                    }
                    break
                }

                if (count >= 4) {
                    return true
                }
                //左斜
                i = x - 1
                var j = y + 1
                count = 0
                while (i >= 0 && j < size) {
                    if (arr[j][i] == TYPE_WHITE) {
                        count++
                        i -= 1
                        j += 1
                        continue
                    }
                    break
                }
                i = x + 1
                j = y - 1
                while (i < size && j >= 0) {
                    if (arr[j][i] == TYPE_WHITE) {
                        count++
                        i += 1
                        j -= 1
                        continue
                    }
                    break
                }
                if (count >= 4) {
                    return true
                }

                //右斜
                i = x - 1
                j = y - 1
                count = 0
                while (i >= 0 && j >= 0) {
                    if (arr[j][i] == TYPE_WHITE) {
                        count++
                        i -= 1
                        j -= 1
                        continue
                    }
                    break
                }
                i = x + 1
                j = y + 1
                while (i < size && j < size) {
                    if (arr[j][i] == TYPE_WHITE) {
                        count++
                        i += 1
                        j += 1
                        continue
                    }
                    break
                }
                if (count >= 4) {
                    return true
                }


            } else {
                //...
                //check横向
                var i = x - 1
                while (i >= 0) {
                    if (arr[y][i] == TYPE_BLACK) {
                        count++
                        i -= 1
                        continue
                    }
                    break
                }
                i = x + 1
                while (i < data!!.size) {
                    if (arr[y][i] == TYPE_BLACK) {
                        count++
                        i += 1
                        continue
                    }
                    break
                }

                if (count >= 4) {
                    return false
                }

                count = 0
                //check纵向
                i = y - 1
                while (i >= 0) {
                    if (arr[i][x] == TYPE_BLACK) {
                        count++
                        i -= 1
                        continue
                    }
                    break
                }
                i = y + 1
                while (i < size) {
                    if (arr[i][x] == TYPE_BLACK) {
                        count++
                        i += 1
                        continue
                    }
                    break
                }

                if (count >= 4) {
                    return false
                }


                //左斜
                i = x - 1
                var j = y + 1
                count = 0
                while (i >= 0 && j < size) {
                    if (arr[j][i] == TYPE_BLACK) {
                        count++
                        i -= 1
                        j += 1
                        continue
                    }
                    break
                }
                i = x + 1
                j = y - 1
                while (i < size && j >= 0) {
                    if (arr[j][i] == TYPE_BLACK) {
                        count++
                        i += 1
                        j -= 1
                        continue
                    }
                    break
                }
                if (count >= 4) {
                    return false
                }

                //右斜
                i = x - 1
                j = y - 1
                count = 0
                while (i >= 0 && j >= 0) {
                    if (arr[j][i] == TYPE_BLACK) {
                        count++
                        i -= 1
                        j -= 1
                        continue
                    }
                    break
                }
                i = x + 1
                j = y + 1
                while (i < size && j < size) {
                    if (arr[j][i] == TYPE_BLACK) {
                        count++
                        i += 1
                        j += 1
                        continue
                    }
                    break
                }
                if (count >= 4) {
                    return false
                }
            }

        }

        return null
    }

    private fun drawGame() {
        val canvas = holder.lockCanvas()
        drawBackground(canvas)
        data?.let { arr ->
            for (y in arr.indices) {
                for (x in arr[y].indices) {
                    val type = arr[y][x]
                    if (type != TYPE_NONE) {

                        canvas.drawCircle(
                            offsetX + x * itemSize,
                            offsetY + y * itemSize,
                            itemSize * 0.4f,
                            if (type == TYPE_WHITE) {
                                pw
                            } else {
                                pb
                            }
                        )
                    }
                }
            }
        }
        holder.unlockCanvasAndPost(canvas)
    }

    private fun computeClickPosition(e: MotionEvent): Pair<Int, Int> {
        var x = e.rawX
        var y = e.rawY
        val itemOffset = itemSize / 3
        if (x < offsetX - itemOffset || y < offsetY - itemOffset) {
            return Pair(-1, -1)
        }

        if (x > offsetX + itemsLength + itemOffset || y > offsetY + itemsLength + itemOffset) {
            return Pair(-1, -1)
        }

        x -= offsetX
        y -= offsetY


        val pair = Pair(
            transToInt((kotlin.math.max(0f, x / itemSize))),
            transToInt((kotlin.math.max(0f, y / itemSize)))
        )
        Log.d(TAG, "computeClickPosition: $pair  $x  $y")
        return pair
    }

    private fun transToInt(value: Float): Int {
        Log.d(TAG, "transToInt() called with: value = $value")
        val intValue = value.toInt()
        val off = value - intValue
        return if (off > 0.5) {
            intValue + 1
        } else {
            intValue
        }
    }

    private fun drawBackground(canvas: Canvas) {
        Log.d(TAG, "drawBackground() called")
        canvas.drawColor(context.resources.getColor(R.color.bg_gobang))

        for (i in 0 until mSizeCount) {
            val start = i * itemSize
            canvas.drawLine(
                offsetX + start, offsetY + 0F, offsetX + start, offsetY + itemsLength, pb
            )
            canvas.drawLine(
                offsetX, offsetY + start, offsetX + itemsLength, offsetY + start, pb
            )
        }

        canvas.drawCircle(
            mWidth.toFloat() / 2, offsetY / 2, itemSize * 0.4f, if (isWhiteDo) {
                pw
            } else {
                pb
            }
        )
    }

    fun bindResultListener(l: Listener) {
        mListener = l
    }

    interface Listener {
        fun onResult(event: Int)
    }
}